package com.apexsoft.assets.base.aspect;


import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.util.IdUtil;
import com.apexsoft.aas.service.model.ADownloadRequest;
import com.apexsoft.aas.service.model.ARequest;
import com.apexsoft.aas.service.model.AUploadRequest;
import com.apexsoft.assets.base.AsyncConfig;
import com.apexsoft.assets.base.request.RequestInfoModel;
import com.apexsoft.assets.base.utils.UserSession;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Map;

/*
 *
 * 调用前日志和异常后日志打印
 */

@Component
@Aspect
@Slf4j
@Order(0)
public class LogAspect {

    @Autowired
    AsyncConfig asyncConfig;

    TimedCache<String, RequestInfoModel> timedCache = CacheUtil.newTimedCache(60*1000);

    private static final ThreadLocal<String> uuidHolder =
            new NamedThreadLocal<String>("UUID");

    private static final String CACHE_NAMESPACE = "LOG";


    @Pointcut("execution(* com.apexsoft.assets.controller..*.*(..))")
    private void logControllerAspect() {
    }

    @Pointcut("execution(* com.apexsoft.zg.productsystem..*.service..*.*(..)) " +
            "&& !execution(* com.apexsoft.zg.productsystem.logserver.service..*.*(..))")
    private void logServiceAspect() {
    }


    /**
     * 执行controller前 获取用户信息，调用的方法及入参
     * @param joinPoint
     */
    @Before("logControllerAspect()")
    public void logBefore(JoinPoint joinPoint) {
        if("com.apexsoft.zg.productsystem.controller.LoginController".equals(joinPoint.getSignature().getDeclaringTypeName())){
            return;
        }
        if(joinPoint.getArgs() == null || joinPoint.getArgs().length == 0){
            return;
        }
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String uuid = IdUtil.randomUUID();
        attributes.getRequest().setAttribute("uuid",uuid);
        String userID = null;
        if (UserSession.getUserSession() != null) {
            userID = UserSession.getUserSession().getUserId();
        }

        //定义请求产生的日志对象并存放request
        RequestInfoModel resqInfo = new RequestInfoModel();
        resqInfo.setUuid(uuid);
        resqInfo.setUserID(userID);
        resqInfo.setIp(getIp()).setUserID(userID)
                .setMethodName(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        StringBuffer sb = new StringBuffer();
        Object[] objects = joinPoint.getArgs();
        for (int i = 0; i < objects.length; ) {
            if(objects[i] == null){
                i++;
                continue;
            }
            sb.append(objects[i].toString());
            i++;
            if (i < objects.length) {
                sb.append(",");
            }
        }
        resqInfo.setParamStr(sb.toString());

        attributes.getRequest().setAttribute("resqInfo",resqInfo);
    }

    /**
     * 调用服务/微服务前 获取请求的uuid，绑定相关调用信息
     * @param point
     */
    @Before("logServiceAspect()")
    public void beforeService(JoinPoint point) {
        if("com.apexsoft.zg.productsystem.customer.service.CacheDataService".equals(point.getSignature().getDeclaringTypeName())){
            return;
        }
        if(point.getArgs() == null || point.getArgs().length == 0){
            return;
        }
        Object[] paramObjs = point.getArgs();
        String uuid = null;
        if(paramObjs == null || paramObjs.length == 0){
            return;
        }
        if(paramObjs[0] instanceof AUploadRequest){
            AUploadRequest aRequest = (AUploadRequest)paramObjs[0];
            Map<String,Object> params = aRequest.getFileInfo().getParams();
            uuid = (String) params.get("uuid");
        }else if(paramObjs[0] instanceof ARequest){
            ARequest aRequest = (ARequest)paramObjs[0];
            uuid = aRequest.getParamEx("uuid",String.class);
        }else if(paramObjs[0] instanceof ADownloadRequest){
            ADownloadRequest aRequest = (ADownloadRequest)paramObjs[0];
            //uuid = aRequest.getParamEx("uuid",String.class);
        }else {
            System.out.println(paramObjs);
        }
        if(uuid != null){
            uuidHolder.set(uuid);
            if(!timedCache.containsKey(uuid)){
                RequestInfoModel resqInfo = new RequestInfoModel();
                resqInfo.setUuid(uuid);
                timedCache.put(uuid,resqInfo);
            }
        }
    }

//    /**
//     * 抛出异常后微服务控制台、日志打印错误信息
//     * @param ex
//     */
//    @AfterThrowing(pointcut = "logServiceAspect()", throwing = "ex")
//    public void afterThrowException(JoinPoint point,Throwable ex) {
//        if("com.apexsoft.zg.productsystem.customer.service.CacheDataService".equals(point.getSignature().getDeclaringTypeName())){
//            return;
//        }
//        if(point.getArgs() == null || point.getArgs().length == 0){
//            return;
//        }
//        RequestInfoModel resqInfo = timedCache.get(uuidHolder.get());
//        log.error("uuid=====>"+uuidHolder.get(),ex);
//        asyncConfig.addsql2Log(resqInfo);
//        timedCache.remove(uuidHolder.get());
//        uuidHolder.remove();
//    }
//
//    /**
//     * 微服务调用完成 删除ThreadLocal中的uuid 避免串用
//     * 发送RequestInfoModel 到日志服务，主要是sql信息
//     */
//    @AfterReturning("logServiceAspect()")
//    public void afterReturnService(JoinPoint point) {
//        if("com.apexsoft.zg.productsystem.customer.service.CacheDataService".equals(point.getSignature().getDeclaringTypeName())){
//            return;
//        }
//        if(point.getArgs() == null || point.getArgs().length == 0){
//            return;
//        }
//        RequestInfoModel resqInfo = timedCache.get(uuidHolder.get());
//        asyncConfig.addsql2Log(resqInfo);
//        timedCache.remove(uuidHolder.get());
//        uuidHolder.remove();
//    }
//
//
//
//    /**
//     * controller 调用完成后获取返回结果的行数 以及程序调用时长（毫秒）
//     * @param point
//     * @param result
//     */
//    @AfterReturning(value = "logControllerAspect()", returning = "result")
//    public void afterReturnController(JoinPoint point, AResponse result) {
//        if("com.apexsoft.zg.productsystem.customer.service.CacheDataService".equals(point.getSignature().getDeclaringTypeName())){
//            return;
//        }
//        if(point.getArgs() == null || point.getArgs().length == 0){
//            return;
//        }
//        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        RequestInfoModel resqInfo = (RequestInfoModel) attributes.getRequest().getAttribute("resqInfo");
//        long rows = 1;
//        if (result.getRecords() != null && !result.getRecords().isEmpty()) {
//            rows = result.getRecords().size();
//        }
//        long duration = 0;
//        if (result.getDuration() != null) {
//            duration = result.getDuration();
//            resqInfo.setDuration(duration);
//            resqInfo.setRows(rows);
//            resqInfo.setType(0);
//            resqInfo.setMsg("执行成功,用时" + duration + "毫秒");
//            //执行成功写入日志
//            log.info(resqInfo.toString());
//            asyncConfig.addLog(resqInfo);
//        }
//    }
//
//    /**
//     * 提醒日志微服务开始 将日志入库
//     * @param point
//     */
//    @AfterThrowing(pointcut = "logControllerAspect()", throwing = "ex")
//    public void afterController(JoinPoint point,Throwable ex) {
//        if("com.apexsoft.zg.productsystem.customer.service.CacheDataService".equals(point.getSignature().getDeclaringTypeName())){
//            return;
//        }
//        if(point.getArgs() == null || point.getArgs().length == 0){
//            return;
//        }
//        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        RequestInfoModel resqInfo = (RequestInfoModel) attributes.getRequest().getAttribute("resqInfo");
//        if(resqInfo==null) {
//            return;
//        }
//        resqInfo.setType(2);
//        LinkedList<Throwable> exList = new LinkedList<>();
//        Throwable t = ex;
//        while(t.getCause() != null){
//            t = t.getCause();
//            exList.addLast(t);
//        }
//        StringBuffer exMsg = new StringBuffer();
//        int i = 0;
//        while (!exList.isEmpty()){
//            i++;
//            if(i<3){
//                exMsg.append(exList.pop().getMessage());
//                exMsg.append("\n");
//            }else if(i < 6){
//                exMsg.append(exList.removeLast().getMessage());
//                exMsg.append("\n");
//            }else {
//                return;
//            }
//
//        }
//        resqInfo.setMsg(exMsg.toString());
//        asyncConfig.addLog(resqInfo);
//    }
//
//    public String getUUID(){
//        return uuidHolder.get();
//    }
//
    private String getIp(){
        String ip = UserSession.getRequestHolder().getHeader("x-real-ip");
        if(ip == null || ip.length() == 0){
            ip = UserSession.getRequestHolder().getRemoteAddr();
        }
        return ip;
    }

    public RequestInfoModel getRequestInfoModel(){
        return timedCache.get(uuidHolder.get());
    }

    public void setRequestInfoModel(RequestInfoModel requestInfoModel){
        timedCache.put(uuidHolder.get(),requestInfoModel);
    }

}
